package work.linruchang.cmd.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import work.linruchang.cmd.CMD;
import work.linruchang.cmd.CMDFactory;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Linux版本的命令工具
 *
 * @author LinRuChang
 * @version 1.0
 * @date 2023/03/27
 * @since 1.8
 **/
@Resource(name= CMDFactory.LINUX)
public class LinuxCMD implements CMD {


    private final String allPort2processCMD = "netstat -tunlp";
    private final String killProcessCMD = "kill -9 {}";

    private LinuxCMD() {};

    @Override
    public List<Integer> getPort(Integer processId) {
        Assert.notNull(processId,"获取端口号失败：进程号缺失，请检查");
        List<String> allPortResults = RuntimeUtil.execForLines(allPort2processCMD);

        List<Integer> targetPortProcessId = allPortResults.stream()
                .map(line -> StrUtil.splitTrim(line, StrUtil.SPACE))
                .filter(lineElems -> StrUtil.startWith(CollUtil.getLast(lineElems), StrUtil.format("{}/", processId)))
                .map(lineElems -> CollUtil.get(lineElems, 3))
                .map(localAddress -> StrUtil.subAfter(localAddress, StrUtil.COLON,true))
                .filter(StrUtil::isNotBlank)
                .map(StrUtil::trimToEmpty)
                .map(Convert::toInt)
                .distinct()
                .sorted()
                .collect(Collectors.toList());
        return targetPortProcessId;
    }

    @Override
    public List<Integer> getProcessId(Integer port) {
        Assert.notNull(port,"获取进程号失败：端口号缺失，请检查");
        List<String> allPortResults = RuntimeUtil.execForLines(allPort2processCMD);

        List<Integer> targetPortProcessId = allPortResults.stream()
                .map(line -> StrUtil.splitTrim(line, StrUtil.SPACE))
                .filter(line -> StrUtil.endWith(CollUtil.get(line,3), StrUtil.format(":{}", port)))
                .map(lineElems -> CollUtil.getLast(lineElems))
                .map(programs -> StrUtil.subBefore(programs, StrUtil.SLASH,false))
                .filter(StrUtil::isNotBlank)
                .map(StrUtil::trimToEmpty)
                .map(Convert::toInt)
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        return targetPortProcessId;
    }

    @Override
    public String killProcess(Integer processId) {
        Assert.notNull(processId,"杀进程失败：进程号缺失，请检查");
        String actualKillProcessCMD = StrUtil.format(killProcessCMD, processId);
        String execResult = RuntimeUtil.execForStr(actualKillProcessCMD);
        return StrUtil.trimToEmpty(StrUtil.blankToDefault(execResult,"成功"));
    }
}
